package com.inplaceedit.client.application;

import com.google.gwt.event.shared.EventBus;
import com.google.gwt.event.shared.SimpleEventBus;
import com.google.gwt.inject.client.AbstractGinModule;
import com.google.gwt.place.shared.PlaceController;
import com.google.gwt.place.shared.PlaceHistoryHandler;
import com.google.gwt.place.shared.PlaceHistoryMapper;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.Singleton;
import com.core.gwt.place.client.PlaceHistoryMapperUsingPlaceType;
import com.inplaceedit.client.activity.main.contact.ContactDetailsActivity;
import com.inplaceedit.client.activity.main.contact.ContactDetailsActivityImpl;
import com.inplaceedit.client.activity.main.contact.ContactDetailsView;
import com.inplaceedit.client.activity.main.contact.ContactNewActivity;
import com.inplaceedit.client.activity.main.contact.ContactNewActivityImpl;
import com.inplaceedit.client.activity.main.contact.ContactNewView;
import com.inplaceedit.client.activity.main.home.HomeActivity;
import com.inplaceedit.client.activity.main.home.HomeActivityImpl;
import com.inplaceedit.client.activity.main.home.HomeView;
import com.inplaceedit.client.activity.menu.MenuActivity;
import com.inplaceedit.client.activity.menu.MenuActivityImpl;
import com.inplaceedit.client.activity.menu.MenuView;
import com.inplaceedit.client.place.HomePlace;
import com.inplaceedit.shared.webservice.CompanyRemoteServiceAsync;
import com.inplaceedit.shared.webservice.ContactRemoteServiceAsync;
import com.inplaceedit.shared.webservice.impl.CompanyRemoteServiceImpl;
import com.inplaceedit.shared.webservice.impl.ContactRemoteServiceImpl;

public class ApplicationModule extends AbstractGinModule {
	static class PlaceControllerProvider implements Provider<PlaceController> {
		private final EventBus eventBus;

		@Inject
		public PlaceControllerProvider(final EventBus eventBus) {
			this.eventBus = eventBus;
		}

		@Override
		public PlaceController get() {
			return new PlaceController(eventBus);
		}
	}

	static class PlaceHistoryHandlerProvider implements
			Provider<PlaceHistoryHandler> {

		private final EventBus eventBus;
		private final PlaceController placeController;
		private final PlaceHistoryMapper placeHistoryMapper;

		@Inject
		private PlaceHistoryHandlerProvider(final EventBus eventBus,
				final PlaceController placeController,
				final PlaceHistoryMapper placeHistoryMapper) {
			this.eventBus = eventBus;
			this.placeController = placeController;
			this.placeHistoryMapper = placeHistoryMapper;
		}

		@Override
		public PlaceHistoryHandler get() {
			final PlaceHistoryHandler placeHandler = new PlaceHistoryHandler(
					placeHistoryMapper);
			placeHandler.register(placeController, eventBus, new HomePlace());
			return placeHandler;
		}
	}

	static class PlaceHistoryMapperProvider implements
			Provider<PlaceHistoryMapper> {

		@Override
		public PlaceHistoryMapper get() {
			final PlaceHistoryMapperUsingPlaceType instance = new PlaceHistoryMapperUsingPlaceType();
			instance.addAll(ApplicationPlaceSet.get());
			return instance;
		}
	}

	@Override
	protected void configure() {
		bind(EventBus.class).to(SimpleEventBus.class).in(Singleton.class);

		bind(PlaceHistoryMapper.class).toProvider(
				PlaceHistoryMapperProvider.class).in(Singleton.class);
		bind(PlaceHistoryHandler.class).toProvider(
				PlaceHistoryHandlerProvider.class).in(Singleton.class);
		bind(PlaceController.class).toProvider(PlaceControllerProvider.class)
				.in(Singleton.class);

		bind(ApplicationShell.class).in(Singleton.class);

		bind(MenuActivity.class).to(MenuActivityImpl.class);
		bind(MenuActivityImpl.View.class).to(MenuView.class)
				.in(Singleton.class);

		bind(HomeActivity.class).to(HomeActivityImpl.class);
		bind(HomeActivityImpl.View.class).to(HomeView.class)
				.in(Singleton.class);

		bind(ContactRemoteServiceAsync.class)
				.to(ContactRemoteServiceImpl.class).in(Singleton.class);

		bind(CompanyRemoteServiceAsync.class)
				.to(CompanyRemoteServiceImpl.class).in(Singleton.class);

		bind(ContactNewActivity.class).to(ContactNewActivityImpl.class);
		bind(ContactNewActivityImpl.View.class).to(ContactNewView.class).in(
				Singleton.class);

		bind(ContactDetailsActivity.class).to(ContactDetailsActivityImpl.class);
		bind(ContactDetailsActivityImpl.View.class)
				.to(ContactDetailsView.class).in(Singleton.class);
	}
}
